package com.ferry.config.api.configutation;

import com.ferry.config.client.FConfigClient;
import com.ferry.config.client.listener.GlobalConfigChangeListener;
import com.google.common.base.Function;
import com.google.common.collect.MapDifference;
import com.google.common.collect.Maps;
import com.netflix.config.ConcurrentMapConfiguration;
import com.netflix.config.DynamicPropertyUpdater;
import com.netflix.config.WatchedUpdateResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.annotation.Nullable;
import java.io.Closeable;
import java.io.IOException;
import java.util.Collections;
import java.util.Map;

/**
 * Created by daiyong
 */
public class FerryConfiguration extends ConcurrentMapConfiguration implements Closeable {

	private static final Logger LOGGER = LoggerFactory.getLogger(FerryConfiguration.class);

	private FConfigClient fConfigClient = FConfigClient.newInstance();

	private final DynamicPropertyUpdater updater = new DynamicPropertyUpdater();

	public FerryConfiguration(String nameSpace, String env) {

		fConfigClient.setNameSpace(nameSpace);
		fConfigClient.setEnv(env);
		fConfigClient.init();

		Map<String, Object> initMap = Collections.<String, Object>unmodifiableMap(fConfigClient.getAllKeyValues());
		updater.updateProperties(WatchedUpdateResult.createFull(initMap), FerryConfiguration.this, false);

		fConfigClient.setGlobalConfigChangeListener(new GlobalConfigChangeListener() {
			@Override
			public void changed(Map<String, String> oldData, Map<String, String> newData) {
				MapDifference<String, Object> diffData = Maps.<String, Object>difference(oldData, newData);
				Map<String, Object> changed = Maps.transformValues(diffData.entriesDiffering(), new Function<MapDifference.ValueDifference<Object>, Object>() {
					@Nullable
					@Override
					public Object apply(@Nullable MapDifference.ValueDifference<Object> input) {
						return input.rightValue();
					}
				});
				WatchedUpdateResult updateResult = WatchedUpdateResult.createIncremental(diffData.entriesOnlyOnRight(), changed, diffData.entriesOnlyOnLeft());
				updater.updateProperties(updateResult, FerryConfiguration.this, false);
			}
		});
	}

	@Override
	public void close() throws IOException {
		fConfigClient.close();
		fConfigClient = null; // help gc
		super.clear();
	}

}
